
package channel;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import log.Log;
import node.ActualNode;
import node.Conversion;
import node.Node;

/**
 * ActualChannel .
 * 
 * @author 558 Team 6
 * @version Spring 2013
 * 
 */
public class ActualChannel extends AbstractChannel
{

  /**
   * serialversion ID.
   */
  private static final long serialVersionUID = 1L;

  /**
   * The channel id (The id of the destination id).
   */
  private final int my_channel_id;

  /**
   * The actual node of the destination node.
   */

  private Node my_actual;

  /** The registry. */
  private final Registry my_registry;

  /**
   * Constructor. Creates the connection channel for every actual nodes.
   * 
   * @param the_node is the actual node this channels starts at.
   * @param the_number is the k value for the connection channel.
   * @param the_m is the total connections from / to one node.
   * @param the_actual_list is the collection of all actual nodes.
   * @param the_registry registry.
   * @throws RemoteException .
   */
  public ActualChannel(final ActualNode the_node, final int the_number, final int the_m,
                       final Object[] the_actual_list, final Registry the_registry)
      throws RemoteException
  {
    super(the_node, the_number, the_m);
    my_node = the_node.getMyID();
    my_channel_id = ((1 << the_number) + my_node) % (1 << the_m);
    my_actual = the_node;
    my_registry = the_registry;
    initializeParentNode(the_actual_list);
  }

  /**
   * Initializes the parent node id for finger table.
   * 
   * @param the_nodes is the collection of all actual nodes.
   */
  private void initializeParentNode(final Object[] the_nodes)
  {
    try
    {
      final int last = the_nodes.length - 1;
      if (my_channel_id < (int) the_nodes[0] || my_channel_id >= (int) the_nodes[last])
      {
        my_actual =
            (Node) my_registry.lookup(Conversion
                .IntToString((int) the_nodes[the_nodes.length - 1]));
      }
      else
      {
        for (int i = 0; i != last; ++i)
        {
          if (my_channel_id >= (int) the_nodes[i] && my_channel_id < (int) the_nodes[i + 1])
          {
            my_actual = (Node) my_registry.lookup(Conversion.IntToString((int) the_nodes[i]));
            break;
          }
        }
      }

    }
    catch (final RemoteException | NotBoundException e)
    {
      e.printStackTrace();
    }
  }

  /**
   * Prints all the connections information to the file.
   * 
   * @param the_log is the output stream.
   */
  public void printLog(final Log the_log)
  {

    try
    {
      the_log.out("The node " + my_node + " is connected to node " + my_channel_id +
                  " and the actual node id is " + my_actual.getMyID());
    }
    catch (final RemoteException e)
    {
      e.printStackTrace();
    }

  }

  /**
   * Find it the node is in the range of interval.
   * 
   * @param the_id is the Id of the node.
   * @return true if it is in the range, otherwise false.
   */
  public boolean isInInterval(final int the_id)
  {
    boolean result = false;
    if (my_lower_limit > my_upper_limit)
    {
      if (the_id >= my_lower_limit || the_id <= my_upper_limit)
      {
        result = true;
      }
    }
    else
    {
      if (the_id >= my_lower_limit && the_id <= my_upper_limit)
      {
        result = true;
      }
    }
    return result;
  }

  /**
   * Queries other nodes in the system.
   * 
   * @param the_id is the node need to pass query to it.
   * @return the actual node that takes charge of the querying node.
   */
  public Node lookup(final int the_id)
  {
    return null;
  }

  /**
   * @return the my_actual
   */
  public Node getActualNode()
  {
    return my_actual;
  }

  /**
   * sets the actual node.
   * 
   * @param the_actual the my_actual to set.
   */
  public void setMyActualNode(final Node the_actual)
  {
    this.my_actual = the_actual;
  }

}
